﻿using AutoMapper;
using FastMvc.Auth;
using FastMvc.Crud.Models;
using FastMvc.Exceptions;
using FastMvc.Models;
using FastMvc.Repositories;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FastMvc.Crud
{
    public class CrudService<TEntity, TEntityDto, TPrimaryKey, TListPageRequestDto, TCreateDto, TUpdateDto> : JQService, ICrudService<TEntity, TEntityDto, TPrimaryKey, TListPageRequestDto, TCreateDto, TUpdateDto>
        where TEntity : DBEntity<TPrimaryKey>, new()
        where TEntityDto : DtoEntity<TPrimaryKey>
        where TListPageRequestDto : ListPageRequestDto, new()
    {
        protected IRepository<TEntity, TPrimaryKey> Repository;

        public CrudService(IRepository<TEntity, TPrimaryKey> repository)
        {
            Repository = repository;
        }


        /// <summary>
        /// 列表查询
        /// </summary>
        public virtual async Task<ListData<TEntityDto>> QueryList(TListPageRequestDto listPageRequest)
        {
            var query = this.SugarClient.Queryable<TEntity>(); 
            var nq = SetSugarQueryable(query);
            if (nq != null)
            {
                query = nq;
            }
            else
            {
                SetSugarQueryable(query, listPageRequest);
            }

            int total = 0;
            var list = await query.ToPageListAsync(listPageRequest.PageIndex, listPageRequest.PageSize, total);

            var Datas = list.Select(t => MapToDto(t).Result).ToList();

            return new ListData<TEntityDto>()
            {
                list = Datas,
                total = total
            };
        }

        /// <summary>
        /// 详情查询
        /// </summary>
        public virtual async Task<TEntityDto> QueryDetail(TPrimaryKey sId)
        {
            var data = await Repository.GetAsync(sId);

            return  await MapToDto(data);
        }

        /// <summary>
        /// 新建
        /// </summary>
        public virtual async Task<TEntityDto> CreateNew(TCreateDto createDto)
        {
            TEntity entity = await MapToEntity(createDto);
            entity = await Repository.InsertAsync(entity);

            return await MapToDto(entity);
        }

        /// <summary>
        /// 修改
        /// </summary>
        public virtual async Task<TEntityDto> Update(TPrimaryKey sId, TUpdateDto updateDto)
        {
            TEntity entity = await MapToEntity(updateDto);
            entity.sId = sId;

            await Repository.UpdateAsync(entity);

            return await MapToDto(entity);
        }

        /// <summary>
        /// 删除
        /// </summary>
        public virtual async Task<TEntityDto> Delete(TPrimaryKey sId)
        {
            var entity = await Repository.GetAsync(sId);
            if (entity == null)
                throw new ApiException("未知的主键Id！");

            await Repository.DeleteAsync(sId);

            return await MapToDto(entity);
        }

        protected virtual ISugarQueryable<TEntity> SetSugarQueryable(ISugarQueryable<TEntity> query, TListPageRequestDto requestDto = null)
        {
            if (requestDto == null)
                return null;
            else
            {
                string[] BaseListColumns = new string[] { "PageIndex", "PageSize", "Sort" };
                var ps = typeof(TListPageRequestDto).GetProperties();
                List<IConditionalModel> wheres = new List<IConditionalModel>();
                foreach (var p in ps)
                {
                    if (!BaseListColumns.Contains(p.Name))
                    {
                        var pValue = p.GetValue(requestDto);
                        if (pValue == null)
                            continue;
                        wheres.Add(new ConditionalModel()
                        {
                            ConditionalType = ConditionalType.Equal,
                            FieldName = p.Name,
                            FieldValue = pValue.ToString(),
                        });
                    }
                }
                if (wheres.Count > 0)
                    query = query.Where(wheres);

                if (!string.IsNullOrEmpty(requestDto.SortSql))
                {
                    query = query.OrderBy(requestDto.SortSql);
                }

                return query;
            }
        }

        protected virtual async Task<TEntityDto> MapToDto(TEntity entity)
        {
            return await Task.FromResult(MapTo<TEntityDto, TEntity>(entity));
        }

        protected virtual async Task<TEntity> MapToEntity<TSource>(TSource source)
        {
            return await Task.FromResult(MapTo<TEntity, TSource>(source));
        }
    }

    public class CrudService<TEntity, TEntityDto, TPrimaryKey, TListPageRequestDto> : CrudService<TEntity, TEntityDto, TPrimaryKey, TListPageRequestDto, TEntityDto, TEntityDto>
        where TEntity : DBEntity<TPrimaryKey>, new()
        where TEntityDto : DtoEntity<TPrimaryKey>
        where TListPageRequestDto : ListPageRequestDto, new()
    {
        public CrudService(IRepository<TEntity, TPrimaryKey> repository)
            : base(repository)
        { }
    }

    public class CrudService<TEntity, TEntityDto, TPrimaryKey> : CrudService<TEntity, TEntityDto, TPrimaryKey, ListPageRequestDto>
        where TEntity : DBEntity<TPrimaryKey>, new()
        where TEntityDto : DtoEntity<TPrimaryKey>
    {
        public CrudService(IRepository<TEntity, TPrimaryKey> repository)
            : base(repository)
        { }
    }

    public class CrudService<TEntity, TEntityDto> : CrudService<TEntity, TEntityDto, string, ListPageRequestDto>
        where TEntity : DBEntity<string>, new()
        where TEntityDto : DtoEntity<string>
    {
        public CrudService(IRepository<TEntity> repository)
            : base(repository)
        { }
    }
}
